---
title: Combining Provider States
---

import charactersProvider from "/docs/concepts/combining_provider_states/characters_provider";
import cityProvider from "/docs/concepts/combining_provider_states/city_provider";
import filteredTodoListProvider from "/docs/concepts/combining_provider_states/filtered_todo_list_provider";
import readInProvider from "/docs/concepts/combining_provider_states/read_in_provider";
import selectAsyncProvider from "/docs/concepts/combining_provider_states/select_async_provider";
import todoListProvider from "/docs/concepts/combining_provider_states/todo_list_provider";
import weatherProvider from "/docs/concepts/combining_provider_states/weather_provider";
import wholeObjectProvider from "/docs/concepts/combining_provider_states/whole_object_provider";
import { Link } from "../../../../../src/components/Link";
import {
  trimSnippet,
  AutoSnippet,
  When,
} from "../../../../../src/components/CodeSnippet";

:::caution
The content of this page may be outdated.  
It will be updated in the future, but for now you may want to refer to the content
in the top of the sidebar instead (introduction/essentials/case-studies/...)
:::

Make sure to read <Link documentID="concepts2/providers"/> first.  
In this guide, we will learn about combining provider states.

## Combining provider states

We've previously seen how to create a simple provider. But the reality is,
in many situations a provider will want to read the state of another provider.

To do that, we can use the [ref] object passed to the callback of our provider,
and use its [watch] method.

As an example, consider the following provider:

<AutoSnippet language="dart" {...cityProvider}></AutoSnippet>

We can now create another provider that will consume our `cityProvider`:

<AutoSnippet language="dart" {...weatherProvider}></AutoSnippet>

That's it. We've created a provider that depends on another provider.

## FAQ

### What if the value being listened to changes over time?

Depending on the provider that you are listening to, the value obtained may
change over time.
For example, you may be listening to a [NotifierProvider], or the provider
being listened to may have been forced to refresh through the use of
[ProviderContainer.refresh]/[ref.refresh].

When using [watch], Riverpod is able to detect that the value being listened to changed
and will _automatically_ re-execute the provider's creation callback when needed.

This can be useful for computed states.
For example, consider a <Link documentID="providers/notifier_provider"/> that exposes a todo-list:

<AutoSnippet language="dart" {...todoListProvider}></AutoSnippet>

A common use-case would be to have the UI filter the list of todos to show
only the completed/uncompleted todos.

An easy way to implement such a scenario would be to:

- create a [StateProvider], which exposes the currently selected filter method:

  ```dart
  enum Filter {
    none,
    completed,
    uncompleted,
  }

  final filterProvider = StateProvider((ref) => Filter.none);
  ```

- make a separate provider which combines the filter method and the todo-list
  to expose the filtered todo-list:

  <AutoSnippet language="dart" {...filteredTodoListProvider}></AutoSnippet>

Then, our UI can listen to `filteredTodoListProvider` to listen to the filtered todo-list.  
Using such an approach, the UI will automatically update when either the filter
or the todo-list changes.

To see this approach in action, you can look at the source code of the [Todo List
example](https://github.com/rrousselGit/riverpod/tree/master/examples/todos).

:::info
This behavior is not specific to [Provider], and works with all providers.

For example, you could combine [watch] with [FutureProvider] to implement a search
feature that supports live-configuration changes:

<AutoSnippet language="dart" {...charactersProvider}></AutoSnippet>

This code will fetch a list of characters from the service, and automatically
re-fetch the list whenever the configurations change or when the search query changes.
:::

### Can I read a provider without listening to it?

Sometimes, we want to read the content of a provider, but without re-creating
the value exposed when the value obtained changes.

An example would be a `Repository`, which reads from another provider the user token
for authentication.  
We could use [watch] and create a new `Repository` whenever the user token changes,
but there is little to no use in doing that.

In this situation, we can use [read], which is similar to [watch], but will not
cause the provider to recreate the value it exposes when the value obtained changes.

In that case, a common practice is to pass the provider's `Ref` to the object created.
The object created will then be able to read providers whenever it wants.

```dart
final userTokenProvider = StateProvider<String>((ref) => null);

final repositoryProvider = Provider(Repository.new);

class Repository {
  Repository(this.ref);

  final Ref ref;

  Future<Catalog> fetchCatalog() async {
    String token = ref.read(userTokenProvider);

    final response = await dio.get('/path', queryParameters: {
      'token': token,
    });

    return Catalog.fromJson(response.data);
  }
}
```

:::danger **DON'T** call [read] inside the body of a provider

<AutoSnippet language="dart" {...readInProvider}></AutoSnippet>

If you used [read] as an attempt to avoid unwanted rebuilds of your object,
refer to [My provider updates too often, what can I do?](#my-provider-updates-too-often-what-can-i-do)
:::

### How to test an object that receives [ref] as a parameter of its constructor?

If you are using the pattern described in [Can I read a provider without listening to it?](#can-i-read-a-provider-without-listening-to-it),
you may be wondering how to write tests for your object.

In this scenario, consider testing the provider directly instead of the raw object.
You can do so by using the [ProviderContainer] class:

```dart
final repositoryProvider = Provider((ref) => Repository(ref));

class Repository {
  Repository(this.ref);

  final Ref ref;
}
```

그러나 `ref.read`를 전달하면 코드가 약간 덜 장황해지고 객체가 `ref.watch`를 사용하지 않을 것입니다.
다시 말해, `ref`대신 `ref.read`를 전달하면 `ref.watch`는 사용할 수 없다는 말과 동일합니다. 

:::

:::위험 **DON'T** : [read]를 프로바이더 내부에서 호출하지 마세요.

```dart
final myProvider = Provider((ref) {
  // 여기서 'read'를 호출하는 것은 좋지 않습니다.
  final value = ref.read(anotherProvider);
});
```

만약 객체의 원치 않는 재빌드을 방지하기 위해 [read]를 사용한 경우,
[프로바이더 갱신이 너무 자주일어나는데 어떻게 개선하면 좋을까요?](#프로바이더-갱신이-너무-자주일어나는데-어떻게-개선하면-좋을까요)
항목을 참고해 주세요.

:::

### 생성자의 매개변수로 [read]를 전달 받는 객체는 어떻게 테스트 하면 좋은가요?

만약 [구독없이 프로바이더를 읽을 수 있나요?](#구독없이-프로바이더를-읽을-수-있나요)에서 사용한 패턴을 사용한다면,
어떻게 객체를 테스트할지 의문이 들 수 있습니다. 

이 시나리오에서는 raw 객체 대신에 프로바이더를 직접 테스트 하는 것이 좋습니다. 
[ProviderContainer] 클래스를 사용하여 테스트를 진행할 수 있습니다. 

```dart
final repositoryProvider = Provider((ref) => Repository(ref.read));

test('fetches catalog', () async {
  final container = ProviderContainer();
  addTearDown(container.dispose);

  Repository repository = container.read(repositoryProvider);

  await expectLater(
    repository.fetchCatalog(),
    completion(Catalog()),
  );
});
```

### My provider updates too often, what can I do?

If your object is re-created too often your provider is likely listening
to objects that it doesn't care about.

For example, you may be listening to a `Configuration` object, but only use the `host`
property.  
By listening to the entire `Configuration` object, if a property other than `host`
changes, this still causes your provider to be re-evaluated – which may be
undesired.

The solution to this problem is to create a separate provider that exposes _only_
what you need in `Configuration` (so `host`):

**AVOID** listening to the entire object:

<AutoSnippet language="dart" {...wholeObjectProvider}></AutoSnippet>

**PREFER** using select when you only need a single property of an object:

<AutoSnippet language="dart" {...selectAsyncProvider}></AutoSnippet>

This will only rebuild the `productsProvider` when the `host` changes.

[provider]: https://pub.dev/documentation/hooks_riverpod/latest/hooks_riverpod/Provider-class.html
[stateprovider]: https://pub.dev/documentation/hooks_riverpod/latest/legacy/StateProvider-class.html
[futureprovider]: https://pub.dev/documentation/hooks_riverpod/latest/hooks_riverpod/FutureProvider-class.html
[statenotifierprovider]: https://pub.dev/documentation/hooks_riverpod/latest/legacy/StateNotifierProvider-class.html
[notifierProvider]: https://pub.dev/documentation/hooks_riverpod/latest/hooks_riverpod/NotifierProvider-class.html
[ref]: https://pub.dev/documentation/riverpod/latest/riverpod/Ref-class.html
[watch]: https://pub.dev/documentation/riverpod/latest/riverpod/Ref/watch.html
[read]: https://pub.dev/documentation/riverpod/latest/riverpod/Ref/read.html
[providercontainer.refresh]: https://pub.dev/documentation/riverpod/latest/riverpod/ProviderContainer/refresh.html
[ref.refresh]: https://pub.dev/documentation/flutter_riverpod/latest/flutter_riverpod/WidgetRef/refresh.html
[providercontainer]: https://pub.dev/documentation/riverpod/latest/riverpod/ProviderContainer-class.html
